package util.ftp.impl;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.PropertyResourceBundle;

import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.net.ftp.FTPConnectionClosedException;
import org.apache.commons.net.io.CopyStreamEvent;
import org.apache.commons.net.io.CopyStreamListener;
import org.apache.commons.net.io.Util;

import sun.net.TelnetInputStream;
import util.ftp.IFtp;


/**
 * @author jack
 * 
 */
public class apacheFtp implements IFtp {

	private static FTPClient ftp;
	private static String host;
	private static int port;
	private static String username;
	private static String password;
	private static String billFileName;
	private final static String fileName = "ftp";
	private static ThreadLocal connection = new ThreadLocal();

	public apacheFtp() {
		this.config();
		ftp = new FTPClient();
	}

	public void config() {
		PropertyResourceBundle resourceBundle = (PropertyResourceBundle) PropertyResourceBundle
				.getBundle(fileName);
		Enumeration enu = resourceBundle.getKeys();
		while (enu.hasMoreElements()) {
			String propertyName = enu.nextElement().toString();
			if (propertyName.equals("ftp.host"))
				host = resourceBundle.getString("ftp.host");
			if (propertyName.equals("ftp.port"))
				port = Integer.parseInt(resourceBundle.getString("ftp.port"));
			if (propertyName.equals("ftp.username"))
				username = resourceBundle.getString("ftp.username");
			if (propertyName.equals("ftp.password"))
				password = resourceBundle.getString("ftp.password");
			if (propertyName.equals("ftp.billFileName"))
				billFileName = resourceBundle.getString("ftp.billFileName");
		}
	}

	/*
	 * 取得檔案並複製一份, 並解開進 List<Hashtable>
	 * 
	 * @see util.ftp.IFtp#getFile()
	 */
	public ArrayList<Hashtable> getFile() throws Exception {
		ArrayList<Hashtable> items = new ArrayList<Hashtable>();
		boolean error = false;

		try {
			int reply;

			ftp.connect(host, port);
			ftp.login(username, password);
			//ftp.setFileType(FTP.BINARY_FILE_TYPE);
			//會導致 org.apache.commons.net.ftp.FTPConnectionClosedException: Connection closed without indication. 的錯誤
			
			// Use passive mode as default because most of us are behind
			// firewalls these days.
			ftp.enterLocalPassiveMode();
			System.out.print(ftp.getReplyString());

			// After connection attempt, you should check the reply code to
			// verify success.
			reply = ftp.getReplyCode();

			if (!FTPReply.isPositiveCompletion(reply)) {
				ftp.disconnect();
				System.err.println("FTP server refused connection.");
				System.exit(1);
			}
			
			// 準備備份的檔案名稱(年月日-時分秒)
			String orgFileName = new File(billFileName).getName();
			String rawBaseName = FilenameUtils.getBaseName(orgFileName);
			String rawExtName = FilenameUtils.getExtension(orgFileName);
			DateFormat df = new SimpleDateFormat("-yyyyMMdd-hhmmss.");
			Date date = new Date();
			String rawFileName = rawBaseName + df.format(date) + rawExtName;
			
			// copy retrive file(複製檔案)
			//String prefix = getServletContext().getRealPath("/");
			String path = new File(".").getCanonicalPath();
			// TODO get ServletContext path(修改為站台路徑)			
			path = path + File.separator + rawFileName; //"foobar.txt";
			OutputStream os = new FileOutputStream(path);

			ftp.retrieveFile(billFileName, os);
			os.close();
			File inFile = new File(path);
//			BufferedReader reader = new BufferedReader(
//					new InputStreamReader(
//							new FileInputStream(inFile), "UTF-8"));
			FileInputStream is = new FileInputStream(inFile);
			InputStreamReader isreader = new InputStreamReader(is, "MS950");
			BufferedReader reader = new BufferedReader(isreader);

			String sourceData;
			String[] sourceDatas;

			Hashtable ht;
			while ((sourceData = reader.readLine()) != null) {
				sourceDatas = sourceData.split(",");
				ht = new Hashtable();
				for (int i = 0; i < sourceDatas.length; i++) {
					ht.put(i, sourceDatas[i].trim());
				}
				items.add(ht);
			}
			reader.close();
			
			ftp.logout();
		} catch (IOException e) {
			error = true;
			e.printStackTrace();
		} finally {
			if (ftp.isConnected()) {
				try {
					ftp.disconnect();
				} catch (IOException ioe) {
					// do nothing
				}
			}
			// System.exit(error ? 1 : 0);
		}
		return items;
	}

	/**
	 * 使用Stream處理檔案
	 * 
	 * @return
	 * @throws Exception
	 */
	public synchronized ArrayList<Hashtable> getFileByStream() throws Exception {
		ArrayList<Hashtable> items = new ArrayList<Hashtable>();
		boolean error = false;

		try {
			int reply;

			ftp.connect(host, port);
			ftp.login(username, password);
			ftp.setFileType(FTP.BINARY_FILE_TYPE);
			// Use passive mode as default because most of us are behind
			// firewalls these days.
			ftp.enterLocalPassiveMode();
			System.out.print(ftp.getReplyString());

			// After connection attempt, you should check the reply code to
			// verify success.
			reply = ftp.getReplyCode();
			if (!FTPReply.isPositiveCompletion(reply)) {
				ftp.disconnect();
				System.err.println("FTP server refused connection.");
				System.exit(1);
			}

			ftp.setCopyStreamListener(createListener());

			InputStream is = ftp.retrieveFileStream(billFileName);
			InputStreamReader isreader = new InputStreamReader(is, "UTF-8");
			BufferedReader reader = new BufferedReader(isreader);
			String sourceData;
			String[] sourceDatas;
			Hashtable ht;
			while ((sourceData = reader.readLine()) != null) {
				sourceDatas = sourceData.split(",");
				ht = new Hashtable();
				for (int i = 0; i < sourceDatas.length; i++) {
					ht.put(i, sourceDatas[i].trim());
				}
				items.add(ht);
			}
			reader.close();
			is.close();
			ftp.logout();
		} catch (IOException e) {
			error = true;
			e.printStackTrace();
		} finally {
			if (ftp.isConnected()) {
				try {
					ftp.disconnect();
				} catch (IOException ioe) {
					// do nothing
				}
			}
			// System.exit(error ? 1 : 0);
		}
		return items;
	}

	public static void main(String[] args) {
		try {
			// Database.getConnection();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public synchronized static void ftpList() {
		boolean error = false;
		try {
			Date date = new Date();
			ftp.connect(host, port);
			System.out.println("Connected at " + date.toLocaleString());
			ftp.login(username, password);
			System.out
					.println("Login successfully at " + date.toLocaleString());

			ftp.setFileType(FTP.BINARY_FILE_TYPE);
			// Use passive mode as default because most of us are behind
			// firewalls these days.
			ftp.enterLocalPassiveMode();

			FTPFile[] list = ftp.listFiles();
			System.out.println("Listing files...");
			for (int i = 0; i < list.length; i++) {
				System.out.println("File ą%" + (i + 1) + ":" + "\t" + list[i]);
			} // displays file name and properties
			ftp.disconnect();
			System.out.println("Disconnected at " + date.toLocaleString()); // displays

			ftp.logout();
		} catch (IOException e) {
			error = true;
			e.printStackTrace();
		} finally {
			if (ftp.isConnected()) {
				try {
					ftp.disconnect();
				} catch (IOException ioe) {
					// do nothing
				}
			}
			// System.exit(error ? 1 : 0);
		}
	}

	private static CopyStreamListener createListener() {
		return new CopyStreamListener() {
			private long megsTotal = 0;

			public void bytesTransferred(CopyStreamEvent event) {
				bytesTransferred(event.getTotalBytesTransferred(), event
						.getBytesTransferred(), event.getStreamSize());
			}

			public void bytesTransferred(long totalBytesTransferred,
					int bytesTransferred, long streamSize) {
				long megs = totalBytesTransferred / 1000000;
				for (long l = megsTotal; l < megs; l++) {
					System.out.print("#");
				}
				megsTotal = megs;
			}
		};
	}

	private static final int IO_BUFFER_SIZE = 4 * 1024;

	private void copyStream(InputStream in, OutputStream out)
			throws IOException {
		// in.reset();
		byte[] b = new byte[IO_BUFFER_SIZE];
		int read;
		while ((read = in.read(b)) != -1) {
			out.write(b, 0, read);
			out.flush();
		}
	}

}
